package adke.models;

import adke.Util;
import adke.gui.Overview;
import adke.gui.panels.LinePanel;
import adke.managers.DropManager;
import adke.managers.GameManager;
import adke.models.powerups.Powerup;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;

public class Line
{
    private Color color;
    private Player player;
    
    // startpunt (pixel absoluut)
    private int startX, startY;
    
    // de volgende waarden zijn allemaal doubles.
    // eerst waren dit allemaal ints, en wat je dan ziet is dat
    // je wel kan sturen, maar heel schokkerig. dat komt 
    // omdat de kleine verandering die dan is aangebracht
    // teniet wordt gedaan omdat het wordt afgerond.
    // we ronden het nu dus pas af als we de absolute coordinaten
    // écht nodig hebben
    
    // punt waar het middelpunt van de lijn nu is
    private double x, y;
    
    // richting in graden
    // 0/360 is naar boven, 90 is naar rechts, 180 naar beneden, 270 naar links
    // kan varieren door powerups
    private double direction;
    
    private boolean left, right;
    
    // hoe ver we van de rand af beginnen
    private int borderStartDistance = 100;
    
    // waarde die aangeeft hoevaak we max (tussen 0 en de max) nog een ovaal mogen tekenen
    // voordat we een gat gaan introduceren
    private int holePaintTimer;
    
    // aantal repaints dat we nog doen voordat we een gat maken
    private int nextHole;
    
    // getal dat aangeeft hoe lang het gat nog moet worden
    private int holeLengthCounter;
    
    // onveranderlijk, tenzij powerup
    private int holeLength;
    
    private double speed;
    
    private double turnSpeed;
    
    private int lineThickness;
    
    public Line(Player owner)
    {
        player = owner;
        color = player.getColor();
    }
    
    public void startRound()
    {
        int fieldW = Overview.getInstance().getGamePanel().getGameWidth()-64; // 32pix spelingranden
        int fieldH = Overview.getInstance().getGamePanel().getGameHeight()-64;
        
        // net als origineel: random beginpunt
        
        startX = borderStartDistance + Util.random(fieldW-(borderStartDistance*2));
        startY = borderStartDistance + Util.random(fieldH-(borderStartDistance*2)); // maar niet zo dicht bij de rand
        
        x = startX;
        y = startY;
        
        // random direction
        direction = Util.random(360);
        
        // we doen een ranodm getal tussen 0 en dit getal
        // dat nieuwe getal is de timer die aftelt wanneer we een gat moeten maken
        holePaintTimer = GameManager.getHoleFrequency();
        
        // laad standaards
        speed = GameManager.getLineSpeed();
        turnSpeed = GameManager.getTurnSpeed();
        lineThickness = GameManager.getLineThickness();
        holeLengthCounter = GameManager.getHoleLength();
        holeLength = holeLengthCounter;
        
        // bereid het eerstvolgende gat voor
        prepareHole();
        
        left = false; right = false;
    }
    
    public Point getCurrentPosition()
    {
        Point p = new Point();
        p.setLocation(x, y);
        return p;
    }
    
    public double getCurrentDirection()
    {
        return direction;
    }
    
    // doe de volgende stap
    public void nextStep()
    {
        // we zijn al dood
        if (!player.isAlive()) return;
        
        if (left)
        {
            direction = direction - turnSpeed;
        }
        
        if (right)
        {
            direction = direction + turnSpeed;
        }
        
        double[] dxdy = Util.calculateNewPointDiff(direction, speed);
        
        x = x + dxdy[0];
        y = y + dxdy[1];
        
        // als we over een powerup heengaan
        if (DropManager.pickingUpPowerup((int)x, (int)y))
        {
            Powerup p = DropManager.pickUpPowerup((int)x, (int)y);
            player.pickUpPowerup(p);
        }
    }
    
    // SPEED
    public double getSpeed()
    {
        return speed;
    }
    
    public void setSpeed(double newSpeed)
    {
        speed = newSpeed;
        
        // we mogenniet stil komen te staan
        if (speed <= 0)
        {
            speed = 1;
        }
        
        // lijn sluit niet meer aan
        if (speed > lineThickness)
        {
            speed = lineThickness;
        }
    }
    
    // TURNS
    public void turnRight()
    {
//        if (direction == 360) direction = 0;
//        direction = direction + GameManager.getTurnSpeed();
        right = true;
    }
    
    public void turnLeft()
    {
//        if (direction == 0) direction = 360;
//        direction = direction - GameManager.getTurnSpeed();
        left = true;
    }
    
    public void straight()
    {
        left = false; right = false;
    }
    
    public double getTurnSpeed()
    {
        return turnSpeed;
    }
    
    public void setTurnSpeed(double newSpeed)
    {
        turnSpeed = newSpeed;
    }
    
    // THICKNESS
    public int getLineThickness()
    {
        return lineThickness;
    }
    
    public void setLineThickness(int newThick)
    {
        lineThickness = newThick;
        
        // lijn mag niet scheuren
        if (lineThickness < speed)
        {
            lineThickness = (int)speed;
        }
    }
    
    // HOLES
    public int getHoleFrequency()
    {
        return holePaintTimer;
    }
    
    public void setHoleFrequency(int newValue)
    {
        holePaintTimer = newValue;
    }
    
    public int getHoleLength()
    {
        return holeLength;
    }
    
    public void setHoleLength(int newValue)
    {
        holeLength = newValue;
    }
    
    public void prepareHole()
    {
        nextHole = Util.random(holePaintTimer);
        
        // de holeLengthCounter moet hier de aantal repaints worden zodat er een gat ontstaat ter grootte
        // van ongeveer de lineThickNess
        
        // eens zien
        // bij elke repaint verschuift het midden van de tekencirkel steeds met *speed*pixels
        // de doorsnede van de tekencirkel is *lineThickNess*
        // bij een speed van 1 moet dit getal dus worden: hetzelfde als lineThickness
        // 
        holeLengthCounter = holeLength;
    }
    
    // teken de huidige positie
    // geeft bounds terug van vlak dat gerepaint moet worden
    public Rectangle paint(Graphics g)
    {
        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);

        g.setColor(color);
        
        // als het tijd is om een gat te tekenen
        if (nextHole == 0)
        {
            // we moeten het gat nog rekken tot het groot genoeg is
            if (holeLengthCounter > 0)
            {
                g.setColor(Color.BLACK);
                holeLengthCounter--;
            }
            
            // het gat is klaar
            else
            {
                // bereid het volgende gat voor
                prepareHole();
            }
        }
        else
        {
            // tel af tot volgende gat
            nextHole--;
        }
        
        // de ovaal wordt altijd vanuit de linker bovenhoek getekend
        // dit betekent dat als we nu de coordinaten teruggeven,
        // deze niet het middelpunt zijn van de ovaal.
        // daarom moeten we de coordinaten een beetje corrigeren
        
        // als we een linethickness van 5 hebben moet het midden van x en y
        // dus ongeveer 3 zijn, in het midden van de ovaal.
        double radius = lineThickness / 2;
        
        // bewaar casts
        int cX = (int)(x-radius);
        int cY = (int)(y-radius);
        
        g.fillOval(cX, cY, lineThickness, lineThickness);
        
        // nu, maak de rect die de bounds aangeeft van het vlak
        // dat veranderd is
        return new Rectangle(cX-1, cY-1, lineThickness + 2, lineThickness + 2); // speling van 1pix aan iedere rand
    }
    
    public void paint()
    {
        // teken de lijn op de buffer
        Rectangle change = paint(LinePanel.getInstance().getPanelGraphics());
        
        // teken de buffer op het scherm zonder automatisch de players weer op de buffer te tekenen
//        LinePanel.getInstance().cleanRepaint();
        
        // dit is veel sneller, doordat we alleen het stukje repainten dat veranderd is
        LinePanel.getInstance().paintRegion(change);
    }
}
